<template>
  <select-cascader
    v-model="arrayValue"
    :props="props"
    v-bind="$attrs"
    v-loading="loading"
    element-loading-spinner="el-icon-loading"
    ref="address"
    @change="handleChange"
    @visible-change="handleVisibleChange"
  ></select-cascader>
</template>
<script>
import { isCancel, CancelToken } from 'axios'
import SelectCascader from './SelectCascaderPanel'
import { addressStructure, addressSplit, addressLevel } from '@vimi/utils-tool'

export default {
  components: {
    SelectCascader,
  },
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    value: String,
    topValue: { type: String, default: '' },
    bottomLevel: { type: Number, default: 4 },
    autoTop: { type: [Boolean, Number], default: false },
  },
  data() {
    return {
      arrayValue: [],
      props: {
        lazy: true,
        multiple: false,
        checkStrictly: true,
        lazyLoad: this.lazyLoad,
      },
      loading: false,
      dropDownVisible: false,
      cancelToken: null,
    }
  },
  computed: {
    queryAddressCode() {
      return this.$store.getters.user.queryAddressCode
    },
    topVal() {
      if (typeof this.autoTop === 'number') {
        return this.queryAddressCode
          .substring(
            0,
            [...addressStructure].splice(0, this.autoTop).reduce((p, c) => p + c, 0)
          )
          .padEnd(12, '0')
      } else {
        return this.autoTop ? this.queryAddressCode : this.topValue
      }
    },
    topLevel() {
      return this.topVal ? addressLevel(this.topVal) : -1
    },
    hasUserId() {
      return !!this.$utils.getUserId()
    },
    addressRef() {
      return this.$refs.address || {}
    },
  },
  watch: {
    value: {
      handler: function (val) {
        this.init(val)
      },
      immediate: true,
    },
  },
  created() {},
  mounted() {},
  methods: {
    init(value) {
      const { panel } = this.$refs.address || {}
      if (panel) panel.activePath = []
      this.arrayValue = addressSplit(value || this.topVal).splice(this.topLevel + 1)
    },

    handleChange() {
      const nodes = this.addressRef.getCheckedNodes()
      const node = (nodes && nodes.length && nodes[0]) || {}
      const value = node.value || this.topVal
      const label = (node.pathLabels || []).join('')
      this.$emit('change', value, node)
      this.$emit('select', label)
    },

    handleVisibleChange(val) {
      this.dropDownVisible = val
    },

    lazyLoad(node, resolve) {
      let { level: nodeLevel = 0, value, root } = node || {}

      if (!this.dropDownVisible) {
        this.loading = true
      }

      if (root) {
        value = this.topVal

        if (this.cancelToken) {
          this.cancelToken()
        }
      }
      nodeLevel += this.topLevel + 1
      setTimeout(() =>
        this.getAddress(value, nodeLevel)
          .then(res =>
            resolve(
              res.map(item => ({
                value: item.id,
                label: item.geoName,
                leaf: nodeLevel >= this.bottomLevel,
              }))
            )
          )
          .catch(err => {
            throw new Error(isCancel(err) ? `Request canceled` : err)
          })
          .finally(this.onLoadFinally)
      )
    },

    async getAddress(address = '', level = 0) {
      return this.$store.dispatch('getAddress', {
        address,
        level,
        config: {
          cancelToken: new CancelToken(c => (this.cancelToken = c)),
        },
      })
    },

    onLoadFinally() {
      this.cancelToken = null

      if (!this.loading) {
        return
      }

      const { loadCount, checkedValue } = this.addressRef.panel || {}
      if (!checkedValue || loadCount >= checkedValue.length) {
        this.loading = false
      }
    },
  },
}
</script>
<style scoped></style>
